package edu.stanford.bmir.protege.web.server.stkosutil.cutter;

import java.util.List;
import java.util.Set;

import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLIndividual;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyChange;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.RemoveAxiom;
import org.semanticweb.owlapi.util.OWLEntityRemover;

import edu.stanford.bmir.protege.web.client.rpc.stkosutil.common.UtilConstants;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.cutter.CuttingResult;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.cutter.RemoveEntityResult;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.statistics.StatisticsResult;
import edu.stanford.bmir.protege.web.server.owlapi.OWLAPIProject;
import edu.stanford.bmir.protege.web.server.owlapi.OWLAPIProjectManager;
import edu.stanford.bmir.protege.web.server.stkosutil.statistics.EntityCounter;
import edu.stanford.bmir.protege.web.shared.project.ProjectId;
import edu.stanford.bmir.protege.web.shared.user.UserId;

public class CutEntityRemover {
	 private OWLAPIProject getProject(String projectName) {
	        if (projectName == null) {
	            throw new NullPointerException("projectName must not be null");
	        }
	        ProjectId projectId = ProjectId.get(projectName);
	        // TODO: Log
	        return getProject(projectId);
	    }

	    /**
	     * Gets the OWLAPIProject for a given {@link ProjectId}.If a project with the specified id exists then that project
	     * will be returned, otherwise, a fresh project will be created and that fresh project returned.
	     * @param projectId The id of the project.
	     * @return The OWL API project. Not <code>null</code>.
	     */
	    private OWLAPIProject getProject(ProjectId projectId) {
	        OWLAPIProjectManager pm = OWLAPIProjectManager.getProjectManager();
	        return pm.getProject(projectId);
	    }
	 //*******************   
	
	public RemoveEntityResult removeEntities(String projectId, UserId userId){
		OWLAPIProject project = this.getProject(projectId);
		 OWLEntityRemover remover = new OWLEntityRemover(project.getRootOntology().getOWLOntologyManager(), project.getRootOntology().getImportsClosure());
	     OWLOntology ontology = project.getRootOntology();
	     
	     Set<OWLClass> sClasses  = ontology.getClassesInSignature();
	     int oldClassNum = sClasses.size();
	     for (OWLClass owlClass: sClasses){
	    	 if (hasCuttingflag(project, owlClass)){
	    		 owlClass.accept(remover);
	    	 }
	     }
	     
	     Set<OWLObjectProperty> sObjectProperties  = ontology.getObjectPropertiesInSignature();
	     int oldObjectPropertyNum = sObjectProperties.size();
	     for (OWLObjectProperty owlObjectProperty: sObjectProperties){
	    	 if (hasCuttingflag(project, owlObjectProperty)){
	    		 owlObjectProperty.accept(remover);
	    	 }
	     }
	     
	     Set<OWLDataProperty> sDataProperties  = ontology.getDataPropertiesInSignature();
	     int oldDataPropertyNum = sDataProperties.size();
	     for (OWLDataProperty owlDataProperty: sDataProperties){
	    	 if (hasCuttingflag(project, owlDataProperty)){
	    		 owlDataProperty.accept(remover);
	    	 }
	     }
	     
	     Set<OWLNamedIndividual> sIndividuals = ontology.getIndividualsInSignature();
	     int oldIndividualNum = sIndividuals.size();
	     for (OWLNamedIndividual individual: sIndividuals){
	    	 if (hasCuttingflag(project, individual)){
	    		 individual.accept(remover);
	    	 }
	     }
	     
	     List<OWLOntologyChange> changeList = remover.getChanges();
	     project.applyChanges(userId, changeList, "删除有剪切标记的Entity");
	     
	     int afterClassNum = ontology.getClassesInSignature().size();
	     int afterObjectPropertyNum = ontology.getObjectPropertiesInSignature().size();
	     int afterDataPropertyNum = ontology.getDataPropertiesInSignature().size();
	     int afterIndividualNum = ontology.getIndividualsInSignature().size();
	     
	     RemoveEntityResult result = new RemoveEntityResult();
	     result.setRemovedClassNum(oldClassNum - afterClassNum);
	     result.setRemovedDataPropertyNum(oldDataPropertyNum - afterDataPropertyNum);
	     result.setRemovedObjectProperyNum(oldObjectPropertyNum - afterObjectPropertyNum);
	     result.setRemovedIndividualNum(oldIndividualNum - afterIndividualNum);
	     result.setRemovedPropertyNum(result.getRemovedDataPropertyNum() + result.getRemovedObjectProperyNum());
	     
	     
	     CuttingResult result1 = new CuttingResult();
	     EntityCounter entityCounter = new EntityCounter();
		 StatisticsResult result2 = entityCounter.countEntities(projectId);
		 result1.setCutClassNumber(result2.getCutClassNumber());
		 result1.setCutIndividualNumber(result2.getCutIndividualNumber());
		 result1.setCutPropertyNumber(result2.getCutPropertyNumber());
		 result1.setTotalClassNumber(result2.getTotalClassNumber());
		 result1.setTotalIndividualNumber(result2.getTotalIndividualNumber());
		 result1.setTotalPropertyNumber(result2.getTotalPropertyNumber());
		 result.setCuttingResult(result1);
	     return result;
	}
	
	private boolean hasCuttingflag(OWLAPIProject project, OWLEntity ownEntity){
		for (OWLAnnotation annotation : ownEntity.getAnnotations(project.getRootOntology(), project.getDataFactory().getRDFSComment())) {
   		 if (annotation.getValue() instanceof OWLLiteral) {
	    		 OWLLiteral commentValue = (OWLLiteral) annotation.getValue();
	    		 String value = commentValue.getLiteral();
	    		  if (value.startsWith(UtilConstants.FLAG_CUTTING)){
	    			 return true;
	    		  }
   		 }//end if
		}//end for
		return false;
	}
}
